package com.niknik.woody.rest;

import com.google.appengine.repackaged.com.google.common.base.Predicate;
import com.google.appengine.repackaged.com.google.common.collect.Collections2;
import com.google.inject.Inject;
import com.niknik.woody.core.ServerToClientTransmitter;
import com.niknik.woody.core.room.GameEx;
import com.niknik.woody.core.room.Room;
import com.niknik.woody.core.room.RoomRegistry;
import com.niknik.woody.rest.response.CreateRoomResponse;
import com.niknik.woody.rest.response.RoomTokenResponse;
import com.niknik.woody.rest.response.RoomsResponse;
import com.niknik.woody.rest.response.WResponse;
import com.niknik.woody.rest.schema.*;
import com.niknik.woody.utils.Check;
import com.niknik.woody.utils.wunit.log.WLog;
import com.niknik.woody.utils.wunit.log.WLogger;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import java.util.Collection;

@Path(ResPath.MAIN)
public class MainRoomRes {

  private static final WLogger log = WLog.get(MainRoomRes.class);

  @Inject private RoomRegistry roomRegistry;
  @Inject private ServerToClientTransmitter serverToClientTransmitter;

  // TODO: player id and room id to strings
  @GET
  @Produces({MediaType.APPLICATION_JSON})
  @Path(ResPath.ROOMS)
  public WResponse getRooms(@QueryParam(ResParam.PLAYER_ID) String playerId) {
    log.methodCall(ResLogMsg.GET_ROOMS_TRACE, playerId);

    Check.argNotNull(playerId, ResParam.PLAYER_ID);

    Collection<Room> rooms = roomRegistry.getRoomsSnapshot();

    rooms = Collections2.filter(rooms, new Predicate<Room>() {

      @Override
      public boolean apply(Room room) {
        return room.isActive();
      }
    });

    return new RoomsResponse(rooms);
  }

  @GET
  @Produces({MediaType.APPLICATION_JSON})
  @Path(ResPath.CREATE)
  public WResponse create(@QueryParam(ResParam.PLAYER_ID) String playerId) {
    log.methodCall(ResLogMsg.CREATE_ROOM_TRACE, playerId);

    Check.argNotNull(playerId, ResParam.PLAYER_ID);

    Room room = roomRegistry.create();
    return new CreateRoomResponse(room);
  }

  @GET
  @Produces({MediaType.APPLICATION_JSON})
  @Path(ResPath.CREATE_CHANNEL)
  public WResponse createChannel(@QueryParam(ResParam.PLAYER_ID) String playerId,
                                 @QueryParam(ResParam.ROOM_ID) String roomId) {
    log.methodCall(ResLogMsg.CREATE_ROOM_CHANNEL_TRACE, playerId, roomId);

    Check.argNotNull(playerId, ResParam.PLAYER_ID);
    Check.argNotNull(roomId, ResParam.ROOM_ID);

    try {
      Room room = roomRegistry.get(roomId);
      Check.state(null != room, ResLogMsg.ROOM_NOT_EXIST, roomId.toString());
      Check.state(room.isActive(), ResLogMsg.ROOM_IS_INACTIVE, roomId.toString());
    }
    catch (IllegalStateException ex) {
      log.exCatch(ex);
      return new WResponse(RespStatus.ERR, RespMsg.ROOM_NOT_REACHABLE);
    }

    String token = serverToClientTransmitter.createChannel(roomId, playerId);
    return new RoomTokenResponse(token);
  }

  @GET
  @Produces({MediaType.APPLICATION_JSON})
  @Path(ResPath.MOVE)
  public WResponse move(@QueryParam(ResParam.ROOM_ID) String roomId, @QueryParam(ResParam.MOVE) String move,
                        @QueryParam(ResParam.PLAYER_ID) String playerId) {
    log.methodCall(ResLogMsg.MOVE_TRACE, playerId, roomId, move);

    Check.argNotNull(playerId, ResParam.PLAYER_ID);
    Check.argNotNull(roomId, ResParam.ROOM_ID);
    Check.strNotEmpty(move, ResParam.MOVE);

    Room room;
    try {
      room = roomRegistry.get(roomId);
      Check.state(null != room, ResLogMsg.ROOM_NOT_EXIST, roomId.toString());
      Check.state(room.isActive(), ResLogMsg.ROOM_IS_INACTIVE, roomId.toString());
    }
    catch (IllegalStateException ex) {
      log.exCatch(ex);
      return new WResponse(RespStatus.ERR, RespMsg.ROOM_NOT_REACHABLE);
    }

    try {
      room.move(playerId, move);
    }
    catch (GameEx ex) {
      log.exCatch(ex);

      return new WResponse(ex);
    }
    return new WResponse();
  }
}
